#ifndef __BUC_CLIENT__
#define __BUC_CLIENT__

#include "datamanage.hpp"
#include "util.hpp"
#include "httplib.h" //与服务端httplib.h相同 可直接使用
#include <string>
#include <vector>
//将Windows.h放置在httplib.h之下包含，防止httplib.h中winsock2.h与Windows.h冲突，因为Windows.h和winsock2.h都有关于网络接口的设计
//但是winsock2.h中没有对接口冲突的判断 而Windows.h中有宏
#include <Windows.h>

namespace cloud
{
	#define SERVER_IP "118.25.144.162"
	#define SERVER_PORT 8668

	class Client
	{
	private:
		std::string _back_dir; //备份文件目录
		DataManage* _data; //数据管理模块
		bool Upload(const std::string& filename) //上传文件
		{
			FileUtil fi(filename);
			std::string body;
			fi.GetContent(&body);
			httplib::Client client(SERVER_IP, SERVER_PORT);
			httplib::MultipartFormData mfd;
			mfd.name = "file"; // 与服务器约定的 上传的是备份文件的标记
			mfd.filename = fi.FileName();
			mfd.content = body;
			mfd.content_type = "application/octet-stream"; //二进制文件流 文件下载格式
			httplib::MultipartFormDataItems items;
			items.push_back(mfd);
			auto res = client.Post("/upload", items);
			if (!res || res->status != 200)
			{
				std::cout << "Back Up File Upload Error!" << std::endl;
				return false;
			}
            return true;
		}

		bool Is_upload(const std::string& filename) //是否满足上传要求
		{
			FileUtil fi(filename);
			std::string logo;
			//如果文件备份信息在客户端中 且 唯一标识没有发生变化 则不需要上传
			if (_data->GetOneByLogo(filename, &logo))
			{
				std::string new_logo = fi.FileName() + "-" + std::to_string(fi.FileSize()) + "-" + std::to_string(fi.FileModTime());
				//判断唯一标识是否相同
				if (logo == new_logo) return false;
			}

			//这里可能发生的问题是 一个很大的文件正在不断拷贝到 back_dir 而程序不知道 会一直将文件上传 导致文件上传很多次
			//这里我们通过判断文件在 n 秒内是否有改动 如果有则上传 (更好的办法:查看文件是否被某进程占用和打开-句柄)
			if (time(nullptr) - fi.FileModTime() < 5) return false; //五秒内被修改则不上传
			
			return true; //否则上传
		}

	public:
		Client(const std::string& back_dir, const std::string& backup_file)
			:_back_dir(back_dir),
			_data(new DataManage(backup_file))
		{}

		void RunModule() //业务处理模块
		{
			std::vector<std::string> filearr;
			FileUtil fi(_back_dir);
			if (fi.Exists() == false) fi.Create_Directory();
			while (1)
			{
				fi.ScanDirectory(&filearr);
				for (auto& path : filearr)
				{
					if (Is_upload(path)) //判断是否可以上传
					{
						if (Upload(path)) //判断上传是否成功
						{
							//上传成功后 将文件备份信息 写入本地数据管理
							FileUtil tmpfi(path);
							//注意:本次使用的是单层级的目录 可以使用文件名tmpfi.FileName() 但是多层级的目录建议直接使用path组成ETag以更好的区分
							std::string logo = tmpfi.FileName() + "-" + std::to_string(tmpfi.FileSize()) + "-" + std::to_string(tmpfi.FileModTime());
							_data->Insert(path, logo);
						}
					}
				}
				Sleep(1000);
			}

		}
	};
}


#endif // !__BUC_CLIENT__

